package com.bridgeintelligent.tag.webserver.security;

import java.util.Arrays;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.web.servlet.AdviceFilter;

import com.bridgeintelligent.tag.constants.TagConstants;
import com.bridgeintelligent.tag.user.mgmt.pojo.User;
import com.bridgeintelligent.tag.utils.SecurityHelper;
import com.bridgeintelligent.tag.webserver.security.session.UserSessionManager;

/**
 * sso token 过滤器
 * 校验、刷新 token
 */
public class SsoTokenFilter extends AdviceFilter {

    /**
     * 如果需要重新登录，就抛出此异常
     */
    static class NeedsReloginException extends RuntimeException {
    }

    /**
     * 过滤器的前置处理
     * 
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     */
    @Override
    protected boolean preHandle(ServletRequest req, ServletResponse resp) {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        try {
            String refreshToken = getCookieValue(request, SsoConstants.COOKIE_SSO_REFRESH_TOKEN);
            String lastAccess = getCookieValue(request, SsoConstants.COOKIE_SSO_LAST_ACCESS);
            String tokenExperes = getCookieValue(request, SsoConstants.COOKIE_SSO_TOKEN_EXPIRES);
            hasExpired(lastAccess, tokenExperes);
            refreshOrRedirect(lastAccess, refreshToken);
        } catch (NeedsReloginException e) {
            logoutAndRedirect(response);
        }
        return true;
    }

    /**
     * 从cookie中获取值
     * 
     * @param request    HttpServletRequest
     * @param cookieName cookie 名称
     * @return cookie 值
     */
    private String getCookieValue(HttpServletRequest request, String cookieName) {
        Cookie[] cookies = request.getCookies();
        Cookie hit = Arrays.stream(cookies).filter(cookie -> cookie.getName().equals(cookieName))
                .findFirst()
                .orElse(null);
        if (hit == null) {
            throw new NeedsReloginException();
        }
        return hit.getValue();
    }

    /**
     * 判断是否过期
     * 
     * @param lastAccess   上一次刷新 toke 的时间戳(毫秒)
     * @param tokenExpires token 的过期时间(秒)
     */
    private void hasExpired(String lastAccess, String tokenExpires) {
        long expiresTimestamp = Long.valueOf(lastAccess) + (Long.valueOf(tokenExpires) * 1000);
        if (expiresTimestamp > System.currentTimeMillis()) {
            throw new NeedsReloginException();
        }
    }

    /**
     * 判断是否需要刷新(续期)
     * 
     * @param lastAccess   上一次刷新 toke 的时间戳(毫秒)
     * @param refreshToken 用于刷新 token 的 token
     */
    private void refreshOrRedirect(String lastAccess, String refreshToken) {
        long lastAccessTimestamp = Long.valueOf(lastAccess) + 300_000;
        if (lastAccessTimestamp < System.currentTimeMillis()) {
            return;
        }
        /*
         * TODO WAYNE
         * 调用 SSO 接口刷新 token
         * 文档中没有相关接口
         */
    }

    /**
     * 退出登录并跳转到首页
     * 
     * @param response 用于重定向页面
     */
    private void logoutAndRedirect(HttpServletResponse response) {
        Object obj = SecurityHelper.shiroSession().getAttribute(TagConstants.SESSION_KEY_OF_USER);
        User currentUser = (User) obj;
        UserSessionManager.newInstance().removeSession(currentUser.getUserId(), null);
        TagSecurityHelper.logout();
    }

}
